package org.jet.emall.reptile.fetcher;


import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.jet.emall.reptile.pojo.ProductInfo;
import org.jet.emall.reptile.service.ProductInfoService;
import org.jet.emall.reptile.utils.HttpClientUtils;
import org.jet.emall.reptile.utils.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Component
public class JDFetcherRunner implements FetcherRunner {

    private Gson gson = new Gson();

    @Value("${fetcher.jd.pages}")
    private int pages;

    @Autowired
    private ProductInfoService productInfoService;

    @Value("${fetcher.jd.urls}")
    private List<String> urls;

    private long num=0;

    //创建线程池
    ExecutorService threadPool = Executors.newFixedThreadPool(20);
    //创建原生阻塞队列  队列最大容量为1000
    BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1000);

    @Override
    public void run() throws Exception {
        //监视队列大小的线程
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //获得队列当前的大小
                    int size = queue.size();
                    System.out.println("当前队列中有" + size + "个pid");
                }
            }
        });

        //开启10个线程去解析手机列表页获得的pids
        for (int i = 1; i <= 10; i++) {
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        String spuCode = null;

                        try {
                            //从队列中取出spuId
                            spuCode = queue.take();
                            Set<String> skuCodes = getAllSkuCode(spuCode);

                            for (String skuCode : skuCodes) {
                                ProductInfo product = parseSKUid(skuCode);
                                if(product==null) {
                                    continue;
                                }
                                product.setSpuCode(spuCode);
                                System.out.println("product=" + product);
                                if(product.getBrand()==null||product.getBrand().isEmpty()
                                    || product.getDetails()==null || product.getDetails().isEmpty()
                                        || product.getImg()==null || product.getImg().isEmpty()
                                        || product.getPrice()==null || product.getPrice().isEmpty()
                                        || product.getPrice().startsWith("-")

                                ) {
                                    continue;
                                }

                                //存入数据库
                                //productInfoService.handleData(product);

                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                            try {
                                //出现异常则放回队列
                                queue.put(spuCode);
                            } catch (InterruptedException e1) {
                                e1.printStackTrace();
                            }
                        }
                    }
                }
            });
        }


        for (int n=0;n<urls.size();n++) {
            //String urlPrefix = urls.get(urls.size()-n-1);
            String urlPrefix = urls.get(n);
            int begin =1;
            pages=2;
            //分页查找数据 共100页
            for (int i = begin; i <= begin+pages; i++) {
                //京东分页page为 1 3 5 7 .....
                //         对应第一页 第二页....

                String url = urlPrefix + (2 * i - 1);
                String html = HttpClientUtils.doGet(url);
                System.out.println("------------从第["+n+"]个url中解析------------------------>");
                parseIndex(html);
            }
        }

    }

    Set<String> getAllSkuCode(String spuId) throws IOException {
        Set<String> skuIds = new HashSet<>();
        skuIds.add(spuId);
        getSkuCodeList(spuId, skuIds);
        return skuIds;
    }

    void getSkuCodeList(String skuId, Set<String> skuCodes) throws IOException {
        int size = skuCodes.size();
        //拼接url 进入手机详情页
        String productUrl = "https://item.jd.com/" + skuId + ".html";
        String productHtml = HttpClientUtils.doGet(productUrl);
        Document document = Jsoup.parse(productHtml);
        Elements elements = document.select("#choose-attrs>.p-choose .item");
        if (elements.size() > 0) {
            List<String> skuCodeList = elements.eachAttr("data-sku");
            skuCodes.addAll(skuCodeList);
            if (size == skuCodes.size()) {
                return;
            } else {
                for (String code : skuCodeList) {
                    getSkuCodeList(code, skuCodes);
                }
            }
        }


    }

    //解析手机列表页
    private void parseIndex(String html) throws IOException, InterruptedException {
        Document document = Jsoup.parse(html);
        //手机列表
        Elements elements = document.select("#J_goodsList>ul>li");

        if (elements != null || elements.size() != 0) {
            for (Element element : elements) {
                //获得每个li的pid
                String spuId = element.attr("data-sku");
                //将pid放入队列中
                queue.put(spuId);
            }
        }
    }

    //解析每个手机的页面 获得某个手机的详细数据
    private ProductInfo parseSKUid(String skuCode) throws IOException {
        System.out.println("开始解析......第["+num+++"]个sku");
        //拼接url 进入手机详情页
        String productUrl = "https://item.jd.com/" + skuCode + ".html";
        String productHtml = HttpClientUtils.doGet(productUrl);
        Document document = Jsoup.parse(productHtml);

        ProductInfo product = new ProductInfo();


        Elements style = document.select("#J-detail-content>style");
        if(style==null || style.size()==0) {
            System.out.println("图片列表有问题...");
            return null;
        }
        String cssText = style.first().html();
        List<String> imgList = StringUtils.getImagesFromCssText(cssText);
        if(imgList==null || imgList.size()==0){
            System.out.println("图片列表有问题------->");
            return null;
        }
        product.setDetails(imgList);
        Elements eles = document.select("#preview>#spec-n1 img");
        if (eles.size() > 0) {

            String src = "https:" + eles.first().attr("data-origin");
            product.setImg(src);
        }

        Elements imagesList = document.select("#spec-list img");

        if(product.getImg().equals("https:"+imagesList.get(0))){
            System.out.println("图片有问题，取消保存...");
            return null;
        }
        List<String> images = new LinkedList<>();
        for(int i=0;i<imagesList.size();i++){
            Element element = imagesList.get(i);
            String src = "https:"+element.attr("src");
            System.out.println("----->src=["+src+"]");
            images.add(src);
        }


        product.setImages(images);

        //获取可选项
        Elements selectx = document.select("#choose-attrs");
        System.out.println("select="+selectx.eachText());

        //获得手机标题
        if (document.select("div.sku-name").size() > 0) {
            String title = document.select("div.sku-name").get(0).text();
            product.setTitle(title);
        }



        //获得手机名称
        //String pname = document.select("[class=parameter2 p-parameter-list] li:first-child").attr("title");


        //获取分类信息
        Elements elementsx = document.select(".crumb-wrap>.w>.crumb>.item");
        String level1Cate = elementsx.get(0).text();
        String level2Cate = elementsx.get(2).text();
        String level3Cate = elementsx.get(4).text();
        //System.out.println("level1Cate=" + level1Cate + ",level2Cate=" + level2Cate + ",level3Cate=" + level3Cate);
        product.setCate1(level1Cate);
        product.setCate2(level2Cate);
        product.setCate3(level3Cate);

        //获得手机品牌
        String brand = document.select("#parameter-brand li").attr("title");
        if(brand==null||brand.isEmpty()){
            brand = elementsx.get(6).text();
        }
        product.setBrand(brand);

        Element last = elementsx.last();
        //System.out.println("last="+last.text());
        //System.out.println("eachText="+elementsx.eachText());

        //product.setPname(pname);
        product.setPname(last.text());

        Elements brList = document.select(".item ul.br-list>li>a");
        List<String> brNameList = brList.eachText();
        if (brNameList.size() > 1) {
            brNameList.remove(brNameList.size() - 1);
            product.setBrands(brNameList);
        }

        //System.out.println("brNameList="+brNameList);

        /*  此方案无法获取到价格
            jd的价格采用异步刷新,price不在返回的html文档中,需要我们去请求价格页面
            Elements select = document.select("span[class=price J-p-" + pid + "]");
            System.out.println(select);
        */

        //拼接价格页面url 经过测试 返回Json数据  jd对IP进行了限制,加入pduid为随机数,是为了可以获取更多数据,但是依然只能爬取部分
        String priceUrl = "https://p.3.cn/prices/mgets?pduid=" + Math.random() + "&skuIds=J_" + skuCode;
        String priceJson = HttpClientUtils.doGet(priceUrl);
        //System.out.println(priceJson);
        Gson gson = new GsonBuilder().create();
        List<Map<String, String>> list = gson.fromJson(priceJson, List.class);
        String price = list.get(0).get("p");
        product.setPrice(price);

        //抓取规格与包装
        String select = ".tab-con>div:nth-child(2)>.Ptable>.Ptable-item";
        Elements elements = document.select(select);
        Map<String, Map<String, String>> specsMap = new HashMap<>();
        if (elements.size() > 0) {
            Iterator<Element> iterator = elements.iterator();

            while (iterator.hasNext()) {
                Element element = iterator.next();
                String h3 = element.select("h3").first().text();
                Map<String, String> specs = new HashMap<>();
                specsMap.put(h3, specs);
                Elements elements1 = element.select(".clearfix");
                Iterator<Element> iterator1 = elements1.iterator();
                while (iterator1.hasNext()) {
                    Element element1 = iterator1.next();
                    String dt = element1.select("dt").first().text();
                    String dd = element1.select("dd").first().text();
                    specs.put(dt, dd);
                }
            }
            if (!specsMap.isEmpty()) {
                product.setSpecs(specsMap);
            }
        }

        //抓取商品介绍中的属性
        select = ".tab-con>div:nth-child(1) ul.p-parameter-list>li";
        Elements elements1 = document.select(select);
        if (elements1 != null && elements.size() > 0) {

            List<String> eachText = elements1.eachText();
            Map<String, String> attrs = new HashMap<>();
            for (String line : eachText) {
                String[] strings = line.split("：");
                if (strings[0].contains("店")) {
                    continue;
                }
                attrs.put(strings[0], strings[1]);
            }
            if(!attrs.isEmpty()){
                product.setAttrs(attrs);
            }
        }


        product.setSkuCode(skuCode);
        return product;
    }


}
